#include "..\mtgp-simple\mtgp32-fast.h"
#include <amp.h>
#include <amp_graphics.h>

/**
    * kernel I/O
    * This structure must be initialized before first use.
    */
#define MTGPDC_MEXP 11213
#define MTGPDC_N 351
struct mtgp32_kernel_status_t 
{
    uint32_t status[MTGPDC_N];
};

//class to cache the basic status and params arrays in vector and AMP formats
//and functions allowing repeated calls to generate random numbers
class mtgp_amp
{
public:
    mtgp_amp(size_t data_size);
    void make_float_random_amp(concurrency::array<float>& d_data);
    void make_float_random_cpu_parallel(vector<float>& h_data);
    void make_float_random_cpu_singlethread(vector<float>& h_data);

private:
    class Params
    {
    public:
        Params(const mtgp32_params_fast_t params[], int blocks);

        vector<uint32_t> pos_tbl;
        vector<uint32_t> sh1_tbl;
        vector<uint32_t> sh2_tbl;
        vector<vector<uint32_t>> param_tbl;
        vector<uint32_t> param_tbl_linear;
        vector<vector<uint32_t>> temper_tbl;
        vector<uint32_t> temper_tbl_linear;
        vector<vector<uint32_t>> single_temper_tbl;
        vector<uint32_t> single_temper_tbl_linear;
        vector<uint32_t> mask;

        //replicate host vectors into array_view
        struct ParamsView
        {
            ParamsView(const Params& params, int blocks);

            const concurrency::array_view<const uint32_t> pos_tbl;
            const concurrency::array_view<const uint32_t> sh1_tbl;
            const concurrency::array_view<const uint32_t> sh2_tbl;
            const concurrency::array_view<const uint32_t, 2> param_tbl;
            const concurrency::array_view<const uint32_t, 2> temper_tbl;
            const concurrency::array_view<const uint32_t, 2> single_temper_tbl;
            const concurrency::array_view<const uint32_t> mask;
        } inner;

        //try replicating host vectors into texture to test performance - seems slower than array_view
        struct ParamsTexture
        {
            ParamsTexture(const Params& params, int blocks);

            const concurrency::graphics::texture<uint32_t,1> pos_tbl;
            const concurrency::graphics::texture<uint32_t,1> sh1_tbl;
            const concurrency::graphics::texture<uint32_t,1> sh2_tbl;
            const concurrency::graphics::texture<uint32_t,2> param_tbl;
            const concurrency::graphics::texture<uint32_t,2> temper_tbl;
            const concurrency::graphics::texture<uint32_t,2> single_temper_tbl;
            const concurrency::graphics::texture<uint32_t,1> mask;
        };
    };

    size_t blocks_max;
    size_t blocks;
    vector<mtgp32_kernel_status_t> h_status;
    concurrency::array_view<mtgp32_kernel_status_t> v_status;
    const Params params;
    const Params::ParamsTexture paramsTexture;
};
